﻿/*
 * Simple and Quick implemention of ImportedPluginProperty
 *
 * This class need further re-architect, but the interfaces will be reserved
 *
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Snowdreamist.Runtime;

namespace Snowdreamist.ComponentModel.Plugin
{
    public class ImportedPluginProperty
    {
        #region static

        public static ImportedPluginProperty<T> Create<T>(ContractMetadata metadata)
        {
            if (metadata == null)
                throw new ArgumentNullException("metadata");
            if (!metadata.IsAvailable<T>())
                throw new InvalidOperationException("Invalid metadata");
            return new ImportedPluginProperty<T>(metadata);
        }

        public static ImportedPluginProperty<T> Create<T>(Guid importedIdentity, Type owner)
        {
            return Create<T>(new ContractMetadata(importedIdentity, null, typeof(T), CandidateMode.One, owner));
        }

        public static ImportedPluginProperty<T, TMetadata> Create<T, TMetadata>(ContractMetadata metadata)
        {
            if (metadata == null)
                throw new ArgumentNullException("metadata");
            if (!metadata.IsAvailable<T>())
                throw new InvalidOperationException("Invalid metadata");
            return new ImportedPluginProperty<T, TMetadata>(metadata);
        }

        public static ImportedPluginProperty<T, TMetadata> Create<T, TMetadata>(Guid importedIdentity, Type owner)
        {
            return Create<T, TMetadata>(new ContractMetadata(importedIdentity, null, typeof(T), CandidateMode.One, owner));
        }

        #endregion static

        public ContractMetadata ContractMetadata { get; private set; }

        #region protected

        protected ImportedPluginProperty(ContractMetadata contractMetadata)
        {
            this.ContractMetadata = contractMetadata;
        }

        #endregion protected
    }

    public class ImportedPluginProperty<T> : ImportedPluginProperty
    {
        public T GetValue(object instance)
        {
            IImportedPluginManager manager = null;

            if (SystemRuntime.Current.TryGetService<IImportedPluginManager>(out manager))
            {
                return manager.GetPlugin<T>(instance, this.ContractMetadata).Plugin;
            }
            else
            {
                throw new InvalidOperationException("Cannot find ImportPluginManager");
            }
        }

        public IEnumerable<T> GetValues(object instance)
        {
            IImportedPluginManager manager = null;

            if (SystemRuntime.Current.TryGetService<IImportedPluginManager>(out manager))
            {
                return manager.GetPlugins<T>(instance, this.ContractMetadata).Select(p => p.Plugin);
            }
            else
            {
                throw new InvalidOperationException("Cannot find ImportPluginManager");
            }
        }

        internal ImportedPluginProperty(ContractMetadata contractMetadata)
            : base(contractMetadata)
        {
        }
    }

    public class ImportedPluginProperty<T, TMetadata> : ImportedPluginProperty<T>
    {
        public ImportedPlugin<T, TMetadata> GetValueWithMetadata(object instance)
        {
            IImportedPluginManager manager = null;

            if (SystemRuntime.Current.TryGetService<IImportedPluginManager>(out manager))
            {
                return manager.GetPlugin<T, TMetadata>(instance, this.ContractMetadata);
            }
            else
            {
                throw new InvalidOperationException("Cannot find ImportPluginManager");
            }
        }

        public IEnumerable<ImportedPlugin<T, TMetadata>> GetValuesWithMetadata(object instance)
        {
            IImportedPluginManager manager = null;

            if (SystemRuntime.Current.TryGetService<IImportedPluginManager>(out manager))
            {
                return manager.GetPlugins<T, TMetadata>(instance, this.ContractMetadata);
            }
            else
            {
                throw new InvalidOperationException("Cannot find ImportPluginManager");
            }
        }

        internal ImportedPluginProperty(ContractMetadata contractMetadata) : base(contractMetadata) { }
    }
}